import {
  Injectable,
  Logger,
  OnModuleInit,
  OnModuleDestroy,
} from '@nestjs/common';
import * as Sentry from '@sentry/node';
import {
  ExceptionReporterInterface,
  ExceptionStatsInterface,
  ExceptionType,
  ExceptionSeverity,
} from '../../exception/exception.interface';

/**
 * Sentry 服务
 * 基于 NestJS 官方示例实现
 * 参考: https://docs.nestjs.cn/fundamentals/dependency-injection
 * 对应 Java: 错误追踪服务
 */
@Injectable()
export class SentryService
  implements
    ExceptionReporterInterface,
    ExceptionStatsInterface,
    OnModuleInit,
    OnModuleDestroy
{
  private readonly logger = new Logger(SentryService.name);
  private initialized = false;
  private stats = new Map<string, number>();

  constructor(private readonly config: any) {
    this.initializeSentry();
  }

  async onModuleInit() {
    if (this.config?.enabled && !this.initialized) {
      try {
        Sentry.init({
          dsn: this.config.dsn,
          environment: this.config.environment || process.env.NODE_ENV,
          release: this.config.release || process.env.npm_package_version,
          tracesSampleRate: this.config.tracesSampleRate || 0.1,
          profilesSampleRate: this.config.profilesSampleRate || 0.1,
          beforeSend: this.beforeSend.bind(this),
          beforeBreadcrumb: this.beforeBreadcrumb.bind(this),
          integrations: [
            // 使用默认集成
          ],
        });

        this.initialized = true;
        this.logger.log('Sentry initialized successfully');
      } catch (error) {
        this.logger.error('Failed to initialize Sentry', error);
      }
    }
  }

  async onModuleDestroy() {
    if (this.initialized) {
      try {
        await Sentry.close(2000);
        this.initialized = false;
        this.logger.log('Sentry closed successfully');
      } catch (error) {
        this.logger.error('Failed to close Sentry', error);
      }
    }
  }

  private initializeSentry() {
    // Sentry 初始化在 onModuleInit 中进行
  }

  // ==================== 异常上报接口 ====================

  /**
   * 上报异常
   */
  async report(exception: any, context?: any): Promise<boolean> {
    if (!this.initialized || !this.shouldReport(exception)) {
      return false;
    }

    try {
      Sentry.withScope((scope) => {
        // 设置标签
        this.setTags(scope, exception, context);

        // 设置上下文
        this.setContext(scope, exception, context);

        // 设置用户信息
        this.setUser(scope, context);

        // 设置额外信息
        this.setExtra(scope, exception, context);

        // 设置级别
        this.setLevel(scope, exception);

        // 捕获异常
        Sentry.captureException(exception);
      });

      return true;
    } catch (error) {
      this.logger.error('Failed to report exception to Sentry', error);
      return false;
    }
  }

  /**
   * 批量上报异常
   */
  async reportBatch(
    exceptions: Array<{ exception: any; context?: any }>,
  ): Promise<boolean[]> {
    const results: boolean[] = [];

    for (const { exception, context } of exceptions) {
      const result = await this.report(exception, context);
      results.push(result);
    }

    return results;
  }

  /**
   * 检查是否应该上报
   */
  shouldReport(exception: any): boolean {
    if (!this.config?.enabled) {
      return false;
    }

    // 根据异常类型和严重程度判断
    const type = this.getExceptionType(exception);
    const severity = this.getExceptionSeverity(exception);

    // 只上报高严重程度的异常
    if (
      severity === ExceptionSeverity.HIGH ||
      severity === ExceptionSeverity.CRITICAL
    ) {
      return true;
    }

    // 某些类型的异常总是上报
    if (
      type === ExceptionType.SYSTEM ||
      type === ExceptionType.INTERNAL_SERVER_ERROR
    ) {
      return true;
    }

    return false;
  }

  // ==================== 异常统计接口 ====================

  /**
   * 记录异常统计
   */
  record(exception: any, context?: any): void {
    const type = this.getExceptionType(exception);
    const severity = this.getExceptionSeverity(exception);

    const key = `${type}:${severity}`;
    const count = this.stats.get(key) || 0;
    this.stats.set(key, count + 1);
  }

  /**
   * 获取异常统计
   */
  getStats(timeRange?: { start: Date; end: Date }): any {
    const stats: any = {
      total: 0,
      byType: {},
      bySeverity: {},
      byTime: [],
      topExceptions: [],
      rate: 0,
      trend: 'stable',
    };

    // 计算统计信息
    for (const [key, count] of this.stats) {
      const [type, severity] = key.split(':');
      stats.total += count;

      stats.byType[type] = (stats.byType[type] || 0) + count;
      stats.bySeverity[severity] = (stats.bySeverity[severity] || 0) + count;
    }

    return stats;
  }

  /**
   * 重置统计
   */
  reset(): void {
    this.stats.clear();
  }

  // ==================== 工具方法 ====================

  /**
   * 设置标签
   */
  private setTags(scope: Sentry.Scope, exception: any, context?: any): void {
    const type = this.getExceptionType(exception);
    const severity = this.getExceptionSeverity(exception);

    scope.setTag('exception.type', type);
    scope.setTag('exception.severity', severity);

    if (context?.request) {
      scope.setTag('http.method', context.request.method);
      scope.setTag('http.url', context.request.url);
      scope.setTag('http.status_code', context.response?.statusCode);
    }

    if (context?.user) {
      scope.setTag('user.id', context.user.id);
      scope.setTag('user.role', context.user.role);
    }

    if (context?.environment) {
      scope.setTag('environment', context.environment.nodeEnv);
      scope.setTag('version', context.environment.version);
    }
  }

  /**
   * 设置上下文
   */
  private setContext(scope: Sentry.Scope, exception: any, context?: any): void {
    if (context?.request) {
      scope.setContext('request', {
        method: context.request.method,
        url: context.request.url,
        headers: this.sanitizeHeaders(context.request.headers),
        body: this.sanitizeBody(context.request.body),
        query: context.request.query,
        params: context.request.params,
        ip: context.request.ip,
        userAgent: context.request.userAgent,
      });
    }

    if (context?.response) {
      scope.setContext('response', {
        statusCode: context.response.statusCode,
        headers: this.sanitizeHeaders(context.response.headers),
        body: this.sanitizeBody(context.response.body),
        size: context.response.size,
      });
    }

    if (context?.environment) {
      scope.setContext('environment', {
        nodeEnv: context.environment.nodeEnv,
        version: context.environment.version,
        hostname: context.environment.hostname,
        pid: context.environment.pid,
      });
    }

    if (context?.trace) {
      scope.setContext('trace', {
        traceId: context.trace.traceId,
        spanId: context.trace.spanId,
        correlationId: context.trace.correlationId,
      });
    }
  }

  /**
   * 设置用户信息
   */
  private setUser(scope: Sentry.Scope, context?: any): void {
    if (context?.user) {
      scope.setUser({
        id: context.user.id,
        username: context.user.username,
        email: context.user.email,
        role: context.user.role,
        permissions: context.user.permissions,
      });
    }
  }

  /**
   * 设置额外信息
   */
  private setExtra(scope: Sentry.Scope, exception: any, context?: any): void {
    if (exception.code) {
      scope.setExtra('error.code', exception.code);
    }

    if (exception.details) {
      scope.setExtra('error.details', exception.details);
    }

    if (exception.cause) {
      scope.setExtra('error.cause', exception.cause);
    }

    if (context?.meta) {
      scope.setExtra('meta', context.meta);
    }
  }

  /**
   * 设置级别
   */
  private setLevel(scope: Sentry.Scope, exception: any): void {
    const severity = this.getExceptionSeverity(exception);

    switch (severity) {
      case ExceptionSeverity.CRITICAL:
        scope.setLevel('fatal');
        break;
      case ExceptionSeverity.HIGH:
        scope.setLevel('error');
        break;
      case ExceptionSeverity.MEDIUM:
        scope.setLevel('warning');
        break;
      case ExceptionSeverity.LOW:
        scope.setLevel('info');
        break;
      default:
        scope.setLevel('error');
    }
  }

  /**
   * 获取异常类型
   */
  private getExceptionType(exception: any): ExceptionType {
    if (exception.name) {
      const name = exception.name.toLowerCase();

      if (name.includes('validation') || name.includes('badrequest')) {
        return ExceptionType.VALIDATION;
      }
      if (name.includes('unauthorized') || name.includes('authentication')) {
        return ExceptionType.AUTHENTICATION;
      }
      if (name.includes('forbidden') || name.includes('authorization')) {
        return ExceptionType.AUTHORIZATION;
      }
      if (name.includes('notfound')) {
        return ExceptionType.NOT_FOUND;
      }
      if (name.includes('conflict')) {
        return ExceptionType.CONFLICT;
      }
      if (name.includes('timeout')) {
        return ExceptionType.TIMEOUT;
      }
      if (name.includes('ratelimit')) {
        return ExceptionType.RATE_LIMIT;
      }
      if (name.includes('database') || name.includes('db')) {
        return ExceptionType.DATABASE;
      }
      if (name.includes('cache')) {
        return ExceptionType.CACHE;
      }
      if (name.includes('network') || name.includes('connection')) {
        return ExceptionType.NETWORK;
      }
      if (name.includes('external') || name.includes('api')) {
        return ExceptionType.EXTERNAL_API;
      }
      if (name.includes('business')) {
        return ExceptionType.BUSINESS;
      }
      if (name.includes('system')) {
        return ExceptionType.SYSTEM;
      }
    }

    if (exception.statusCode) {
      switch (exception.statusCode) {
        case 400:
          return ExceptionType.BAD_REQUEST;
        case 401:
          return ExceptionType.AUTHENTICATION;
        case 403:
          return ExceptionType.AUTHORIZATION;
        case 404:
          return ExceptionType.NOT_FOUND;
        case 409:
          return ExceptionType.CONFLICT;
        case 429:
          return ExceptionType.RATE_LIMIT;
        case 500:
          return ExceptionType.INTERNAL_SERVER_ERROR;
        case 503:
          return ExceptionType.SERVICE_UNAVAILABLE;
        default:
          return ExceptionType.UNKNOWN;
      }
    }

    return ExceptionType.UNKNOWN;
  }

  /**
   * 获取异常严重程度
   */
  private getExceptionSeverity(exception: any): ExceptionSeverity {
    const type = this.getExceptionType(exception);

    switch (type) {
      case ExceptionType.INTERNAL_SERVER_ERROR:
      case ExceptionType.SYSTEM:
        return ExceptionSeverity.CRITICAL;
      case ExceptionType.AUTHENTICATION:
      case ExceptionType.AUTHORIZATION:
      case ExceptionType.DATABASE:
      case ExceptionType.NETWORK:
        return ExceptionSeverity.HIGH;
      case ExceptionType.VALIDATION:
      case ExceptionType.BAD_REQUEST:
      case ExceptionType.CONFLICT:
      case ExceptionType.CACHE:
      case ExceptionType.EXTERNAL_API:
        return ExceptionSeverity.MEDIUM;
      case ExceptionType.NOT_FOUND:
      case ExceptionType.TIMEOUT:
      case ExceptionType.RATE_LIMIT:
      case ExceptionType.BUSINESS:
        return ExceptionSeverity.LOW;
      default:
        return ExceptionSeverity.MEDIUM;
    }
  }

  /**
   * 清理请求头
   */
  private sanitizeHeaders(
    headers: Record<string, string>,
  ): Record<string, string> {
    const sanitized: Record<string, string> = {};
    const sensitiveHeaders = [
      'authorization',
      'cookie',
      'x-api-key',
      'x-auth-token',
    ];

    for (const [key, value] of Object.entries(headers)) {
      if (sensitiveHeaders.includes(key.toLowerCase())) {
        sanitized[key] = '[REDACTED]';
      } else {
        sanitized[key] = value;
      }
    }

    return sanitized;
  }

  /**
   * 清理请求体
   */
  private sanitizeBody(body: any): any {
    if (!body) return body;

    if (typeof body === 'string') {
      try {
        const parsed = JSON.parse(body);
        return this.sanitizeObject(parsed);
      } catch {
        return body;
      }
    }

    if (typeof body === 'object') {
      return this.sanitizeObject(body);
    }

    return body;
  }

  /**
   * 清理对象
   */
  private sanitizeObject(obj: any): any {
    if (!obj || typeof obj !== 'object') return obj;

    const sanitized = { ...obj };
    const sensitiveFields = ['password', 'token', 'secret', 'key', 'auth'];

    for (const field of sensitiveFields) {
      if (sanitized[field]) {
        sanitized[field] = '[REDACTED]';
      }
    }

    return sanitized;
  }

  /**
   * 发送前处理
   */
  private beforeSend(event: Sentry.Event): Sentry.Event | null {
    // 过滤敏感信息
    if (event.extra) {
      event.extra = this.sanitizeObject(event.extra);
    }

    if (event.contexts) {
      event.contexts = this.sanitizeObject(event.contexts);
    }

    if (event.tags) {
      event.tags = this.sanitizeObject(event.tags);
    }

    return event;
  }

  /**
   * 面包屑前处理
   */
  private beforeBreadcrumb(
    breadcrumb: Sentry.Breadcrumb,
  ): Sentry.Breadcrumb | null {
    // 过滤敏感信息
    if (breadcrumb.data) {
      breadcrumb.data = this.sanitizeObject(breadcrumb.data);
    }

    return breadcrumb;
  }

  // ==================== 公共方法 ====================

  /**
   * 手动捕获异常
   */
  captureException(exception: any, context?: any): void {
    if (this.initialized) {
      Sentry.withScope((scope) => {
        this.setTags(scope, exception, context);
        this.setContext(scope, exception, context);
        this.setUser(scope, context);
        this.setExtra(scope, exception, context);
        this.setLevel(scope, exception);

        Sentry.captureException(exception);
      });
    }
  }

  /**
   * 手动捕获消息
   */
  captureMessage(
    message: string,
    level: Sentry.SeverityLevel = 'info',
    context?: any,
  ): void {
    if (this.initialized) {
      Sentry.withScope((scope) => {
        if (context) {
          this.setContext(scope, null, context);
          this.setUser(scope, context);
          this.setExtra(scope, null, context);
        }

        scope.setLevel(level);
        Sentry.captureMessage(message);
      });
    }
  }

  /**
   * 开始事务
   */
  startTransaction(name: string, op: string): any {
    if (this.initialized) {
      // 新版本 Sentry API 已变更，暂时返回 null
      return null;
    }
    return null;
  }

  /**
   * 获取当前事务
   */
  getCurrentTransaction(): any {
    if (this.initialized) {
      // 新版本 Sentry API 已变更，暂时返回 undefined
      return undefined;
    }
    return undefined;
  }

  /**
   * 设置用户上下文
   */
  setUserContext(user: {
    id: string;
    username?: string;
    email?: string;
    role?: string;
  }): void {
    if (this.initialized) {
      Sentry.setUser(user);
    }
  }

  /**
   * 设置标签
   */
  setTag(key: string, value: string): void {
    if (this.initialized) {
      Sentry.setTag(key, value);
    }
  }

  /**
   * 设置上下文（公共方法）
   */
  setContextPublic(key: string, context: any): void {
    if (this.initialized) {
      Sentry.setContext(key, context);
    }
  }

  /**
   * 设置额外信息（公共方法）
   */
  setExtraPublic(key: string, value: any): void {
    if (this.initialized) {
      Sentry.setExtra(key, value);
    }
  }

  /**
   * 设置级别（公共方法）
   */
  setLevelPublic(level: Sentry.SeverityLevel): void {
    if (this.initialized) {
      // 新版本 Sentry API 已变更，暂时不执行
      // Sentry.setLevel(level);
    }
  }

  /**
   * 添加面包屑
   */
  addBreadcrumb(breadcrumb: Sentry.Breadcrumb): void {
    if (this.initialized) {
      Sentry.addBreadcrumb(breadcrumb);
    }
  }

  /**
   * 配置作用域
   */
  configureScope(callback: (scope: Sentry.Scope) => void): void {
    if (this.initialized) {
      // 新版本 Sentry API 已变更，暂时不执行
      // Sentry.configureScope(callback);
    }
  }

  /**
   * 使用作用域
   */
  withScope(callback: (scope: Sentry.Scope) => void): void {
    if (this.initialized) {
      Sentry.withScope(callback);
    }
  }
}
